package org.mmtk.plan.scale;

import org.mmtk.plan.StopTheWorldMutator;
import org.mmtk.policy.Space;
import org.mmtk.utility.Log;
import org.mmtk.utility.alloc.Allocator;
import org.mmtk.utility.options.Options;
import org.vmmagic.pragma.Inline;
import org.vmmagic.pragma.Uninterruptible;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.ObjectReference;

@Uninterruptible
public class ScaleMutator extends StopTheWorldMutator {
	protected ScaleMarkSweepLocal localScalMS = new ScaleMarkSweepLocal(Scale.scaleSpace);

	@Inline
	@Override
	public Address alloc(int bytes, int align, int offset, int allocator,
			int site) {
		if (allocator == Scale.ALLOC_DEFAULT) {
			Address result = localScalMS.alloc(bytes, align, offset);
			if(Options.scaleDebug.getValue() > 9) {
				Log.write("alloc, bytes=");
				Log.write(bytes);
				Log.write(", align=");
				Log.write(align);
				Log.write(", offset=");
				Log.write(offset);
				Log.write(", result=");
				Log.writeln(result);
				Log.flush();
			}
			return result;
		}
		return super.alloc(bytes, align, offset, allocator, site);
	}

	@Inline
	@Override
	public void postAlloc(ObjectReference ref, ObjectReference typeRef,
			int bytes, int allocator) {
		if (allocator == Scale.ALLOC_DEFAULT)
			Scale.scaleSpace.postAlloc(ref);
		else
			super.postAlloc(ref, typeRef, bytes, allocator);
	}

	public Space getSpaceFromAllocator(Allocator a) {
		if (a == localScalMS)
			return Scale.scaleSpace;
		return super.getSpaceFromAllocator(a);
	}

	@Override
	public Allocator getAllocatorFromSpace(Space space) {
		if (space == Scale.scaleSpace)
			return localScalMS;
		return super.getAllocatorFromSpace(space);
	}

	@Inline
	@Override
	public void collectionPhase(short phaseId, boolean primary) {
		if (phaseId == Scale.PREPARE) {
			super.collectionPhase(phaseId, primary);
			localScalMS.prepare();
			return;
		}

		if (phaseId == Scale.RELEASE) {
			localScalMS.release();
			super.collectionPhase(phaseId, primary);
			return;
		}

		super.collectionPhase(phaseId, primary);
	}

	@Override
	public void flush() {
		super.flush();
		localScalMS.flush();
	}
}
